﻿using LuaInterface;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public class ScriptManager : CommonLib.LazySingleton<ScriptManager>
{
	private LuaState m_Lua = null;
	private LuaLooper m_Looper = null;

	public Dictionary<string, LuaFunction> funcMap = new Dictionary<string, LuaFunction>();


	public ScriptManager() {
		m_Lua = new LuaState();
		m_Lua.Start();
		m_Lua.LuaSetTop(0);

		LuaBinder.Bind(m_Lua);
		DelegateFactory.Init();

		this.BootSubCortine();
	}

	void BootSubCortine()
	{
		m_Looper = new GameObject().AddComponent<LuaLooper>();
		m_Looper.luaState = m_Lua;
		LuaCoroutine.Register(m_Lua, m_Looper);
	}

	internal void BootSubLoadFile(IList lstFile, System.Action callBack = null)
	{
#if UNITY_EDITOR
		List<UnityEngine.Object> ret = new List<Object>();
		EditorUtil.GetAllAssets<UnityEngine.Object>("Assets/ResourceUpdate/Scripts", null, ref ret);
		foreach (var obj in ret)
		{
			var asset = obj as TextAsset;
			if (asset != null) {
				Debug.Log(asset.text);
				m_Lua.DoString(asset.text, asset.name);
			}
		}
#endif
		callBack?.Invoke();
	}

	internal void BootSubLoadFileFromBundle(IList bundles) { }


	public void DoUpdate()
	{
		if (null != m_Lua)
		{
			if (!m_Lua.CheckTop())
			{
				//ShutDown or Exit
			}

		}
	}

	protected LuaFunction GetLuaFunction(string funcName)
	{
		LuaFunction func = null;
		if (Application.isPlaying)
		{
			if (!funcMap.TryGetValue(funcName, out func))
			{
				func = this.m_Lua.GetFunction(funcName, true);
				if (func != null)
					this.funcMap.Add(funcName, func);
			}
		}
		else
		{
			//直接获取 刷新更改
			func = this.m_Lua.GetFunction(funcName, true);
		}
		return func;
	}

	#region 处理值类型
	public bool CallFunctionValue<T>(string funcName, object[] param, out T value)  //where T : System.ValueType
	{
		value = default;
		if (string.IsNullOrEmpty(funcName)) return false;
		LuaFunction func = GetLuaFunction(funcName);
		if (func == null) return false;
		try
		{
			func.BeginPCall();
			if (param != null)
				func.PushArgs(param);
			func.PCall();
			value = func.CheckValue<T>();
			func.EndPCall();
			return true;
		}
		catch (LuaException le) {
			Debug.LogError($"调用方法(Value)异常/n {le.StackTrace}");
			return false;
		}
	}

	public bool CallFunctionValue<T>(ScriptObject so, string funcName, object[] param, out T value)
	{
		return CallFunctionValue<T>(GetGlobalFunctionName(so, funcName), param, out value);
	}
	#endregion

	#region 处理引用类型
	public bool CallFunction(string funcName, object[] param, out object obj)  //where T : System.ValueType
	{
		obj = default;
		if (string.IsNullOrEmpty(funcName)) return false;
		LuaFunction func = GetLuaFunction(funcName);
		if (func == null) return false;

		try
		{
			func.BeginPCall();
			if (param != null)
				func.PushArgs(param);
			func.PCall();
			obj = func.CheckVariant();
			func.EndPCall();
			return true;
		}
		catch (LuaException le)
		{
			Debug.LogError($"调用方法(object)异常/n {le.StackTrace}"); 
			return false;
		}
	}

	public bool CallFunction(string funcName, object[] param, out object[] obj)  //where T : System.ValueType
	{
		obj = default;
		if (string.IsNullOrEmpty(funcName)) return false;
		LuaFunction func = GetLuaFunction(funcName);
		if (func == null) return false;

		try
		{
			func.BeginPCall();
			if (param != null)
				func.PushArgs(param);
			func.PCall();
			obj = func.CheckObjects();
			func.EndPCall();
			return true;
		}
		catch (LuaException le)
		{
			Debug.LogError($"调用方法(object)异常/n {le.StackTrace}");
			return false;
		}
	}

	public bool CallFunction(ScriptObject so, string funcName, object[] param, out object obj) {
		return CallFunction(GetGlobalFunctionName(so, funcName), param, out obj);
	}

	public bool CallFunction(ScriptObject so, string funcName, object[] param, out object[] objs)
	{
		return CallFunction(GetGlobalFunctionName(so, funcName), param, out objs);
	}

	protected string GetGlobalFunctionName(ScriptObject so, string funcName)
	{
		string glName;

		glName = System.gstring.Concat(so.LuaClassName,"." ,funcName).ToString();
		return glName;
		
	}
	#endregion

	#region 不含返回值
	public bool CallFunction(string funcName, object[] param)
	{
		if (string.IsNullOrEmpty(funcName)) return false;
		LuaFunction func = GetLuaFunction(funcName);
		if (func == null) return false;

		try
		{
			func.BeginPCall();
			if (param != null)
				func.PushArgs(param);
			func.PCall();
			func.EndPCall();
			return true;
		}
		catch (LuaException le)
		{
			Debug.LogError($"调用方法(object)异常/n {le.StackTrace}");
			return false;
		}
	}

	public bool CallFunction(ScriptObject so, string funcName, object[] param)
	{
		return CallFunction(GetGlobalFunctionName(so, funcName), param);
	}
	#endregion

	public void Gc()
	{
		if (m_Lua != null)
			m_Lua.Collect();
	}

	public void ShowDown() {
		if (!m_Lua.CheckTop())
			Debug.LogError("当前还有正在执行的指令");
		if (null != m_Looper)
			m_Looper.Destroy();
		m_Looper = null;
		m_Lua.Dispose();
		m_Lua = null;
	}

	#region
	public LuaTable GetTable(string tableName)
	{
		if (m_Lua == null || string.IsNullOrEmpty(tableName))
			return null;
		LuaTable table = m_Lua.GetTable(tableName);
		if (table == null)
			Debug.Log($"找不到 {tableName}");
		return table;
	}
	#endregion
}
